/**
	2025-6-30 
	+ double get_relative_error(int max, int min);

	2025-7-17
	+ void u8_to_u32_array(const uint8_t *src, uint32_t src_len, uint32_t *dest, uint8_t endian) 
	
	2025-9-23
	+ u8_to_u16_array
	+ u16_to_u8_array
	
	2025-9-24
	+ crc_ccitt

    2025-10-10
    + u8_to_u32_array 增加任意填充参数
*/



#include "conver_tool.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>




static uint16_t CRC16Table[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};

uint16_t crc_ccitt(uint8_t *q, uint16_t len)
{
	uint16_t crc = 0;
	
	while (len-- > 0)
	{		
		crc = CRC16Table[(crc >> 8 ^ *q++) & 0xff] ^ (crc << 8);
	}
	return ~crc;
}

/********************************************************************************************
*函数功能:判断value是否在范围内，双闭区间
*参数:  
*返回值:
********************************************************************************************/
int isInRange(int value, int min, int max) 
{
    return (value >= min) && (value <= max);
}



/********************************************************************************************
*函数功能:将U8数据拼接为 U16的数组 
*参数:  src： 		U8数组  
		src_len：	U8数组长度，最长为16
		dest：		U16数组 需要数组长度为4
		endian： 	0 = 小端， 1 = 大端
*返回值:
********************************************************************************************/
uint16_t u8_to_u16_array(uint16_t *u16_buff, const uint8_t *u8_buff,
							uint16_t u8_len, EndianMode endian) 
{
    if (u8_buff == NULL || u16_buff == NULL || u8_len == 0) {
        return 0; // 无效输入
    }

    // 计算输出的u16数组长度（向上取整）
    uint16_t u16_len = (u8_len + 1) / 2;
    // 初始化输出数组（确保未使用的字节补0）
    memset(u16_buff, 0, u16_len * sizeof(uint16_t));

    for (uint16_t i = 0; i < u8_len; i++) 
	{
        uint16_t u16_idx = i / 2; // 当前u16元素的索引
        uint8_t byte_pos = i % 2; // 0：第一个字节，1：第二个字节

        if (endian == ENDIAN_BIG) {
            // 大端模式：第一个字节为高8位，第二个为低8位
            if (byte_pos == 0) {
                u16_buff[u16_idx] = (uint16_t)u8_buff[i] << 8; // 高8位
            } else {
                u16_buff[u16_idx] |= u8_buff[i]; // 低8位
            }
        } else {
            // 小端模式：第一个字节为低8位，第二个为高8位
            if (byte_pos == 0) {
                u16_buff[u16_idx] = u8_buff[i]; // 低8位
            } else {
                u16_buff[u16_idx] |= (uint16_t)u8_buff[i] << 8; // 高8位
            }
        }
    }

    return u16_len;
}



/********************************************************************************************
*函数功能:将U16数据拆为 U8的数组 
*参数:  src： 		U8数组  
		src_len：	U8数组长度，最长为16
		dest：		U16数组 需要数组长度为4
		endian： 	0 = 小端， 1 = 大端
*返回值:
********************************************************************************************/
uint32_t u16_to_u8_array(uint8_t *u8_buff, const uint16_t *u16_buff, uint32_t u16_len,  EndianMode endian)
{
    // 参数合法性检查
    if (u16_buff == NULL || u8_buff == NULL || u16_len == 0) {
        return 0;
    }

    uint32_t dest_idx = 0;  // 目标数组索引
    for (uint32_t i = 0; i < u16_len; i++) {
        uint16_t val = u16_buff[i];  // 当前16位数据

        if (endian == ENDIAN_BIG) {
            // 大端模式：先存高8位，再存低8位
            u8_buff[dest_idx++] = (uint8_t)(val >> 8);   // 高8位
            u8_buff[dest_idx++] = (uint8_t)(val & 0xFF); // 低8位
        } else {
            // 小端模式：先存低8位，再存高8位
            u8_buff[dest_idx++] = (uint8_t)(val & 0xFF); // 低8位
            u8_buff[dest_idx++] = (uint8_t)(val >> 8);   // 高8位
        }
    }

    return dest_idx;  // 返回转换后的字节总数（u16_len * 2）
}



/********************************************************************************************
*函数功能:将U8数据拼接为 4个U32的数组 
*
*参数：
* 将uint8_t数组转换为4个uint32_t的数组，空余部分用指定字节值补齐
* @param src：源uint8_t数组（可为NULL，此时全部用pad_value填充）
* @param src_len：源数组长度（字节数）
* @param dest：目标uint32_t数组（需预先分配4个元素的空间）
* @param endian：大小端模式（0 = 小端， 1 = 大端）
* @param pad_value：用于补齐的字节值（0x00~0xFF任意值）
*
*返回值:
********************************************************************************************/
void u8_to_u32_array(const uint8_t *src, uint32_t src_len, 
                     uint32_t *dest, EndianMode endian, uint8_t pad_value) 

{
    // 检查目标数组有效性
    if (dest == NULL) {
        return;
    }
    
    // 1. 用指定填充值初始化目标数组（4个uint32_t共16字节）
    // 每个字节都填充pad_value，例如pad_value=0xAA时，每个uint32_t初始为0xAAAAAAAA
    memset(dest, pad_value, 4 * sizeof(uint32_t));
    
    // 2. 计算需要处理的源数据字节数（最多16字节）
    uint32_t total_bytes = (src_len > 16) ? 16 : src_len;
    
    // 3. 用源数据覆盖目标数组的对应位置
    for (uint32_t i = 0; i < total_bytes; i++) {
        uint32_t u32_index = i / 4;  // 目标uint32_t的索引（0~3）
        uint32_t byte_pos = i % 4;   // 字节在uint32_t中的位置（0~3）
        
        // 源数组为NULL时，保持填充值不变
        if (src == NULL) {
            continue;
        }
        
        // 清除目标位置的填充值，写入源数据（关键步骤）
        uint32_t src_byte = (uint32_t)src[i];  // 源字节值
        if (endian == ENDIAN_BIG) {
            // 大端模式：高位字节在前（字节0对应uint32_t的bit24~31）
            dest[u32_index] &= ~((uint32_t)0xFF << (8 * (3 - byte_pos)));  // 清除填充值
            dest[u32_index] |= src_byte << (8 * (3 - byte_pos));           // 写入源字节
        } else {
            // 小端模式：低位字节在前（字节0对应uint32_t的bit0~7）
            dest[u32_index] &= ~((uint32_t)0xFF << (8 * byte_pos));         // 清除填充值
            dest[u32_index] |= src_byte << (8 * byte_pos);                  // 写入源字节
        }
    }
}




/*********************************************************************************************
 * 将两个u8合并为一个u16
 * @param high - 高8位字节
 * @param low - 低8位字节
 * @return 合并后的u16值
 ********************************************************************************************/
uint16_t u8_to_u16(uint8_t high, uint8_t low) 
{
    return (uint16_t)(high << 8) | low;
}

/*********************************************************************************************
 * 将一个u32分解为4个u8
 * @param value - 待分解的u32值
 * @param bytes - 存储分解结果的数组(至少4字节)
 * @param big_endian - 是否使用大端序(高字节在前)
 ********************************************************************************************/
void u32_to_u8_array(uint32_t value, uint8_t bytes[4], EndianMode big_endian) 
{
    if (big_endian) {
        bytes[0] = (value >> 24) & 0xFF;  // 最高字节
        bytes[1] = (value >> 16) & 0xFF;
        bytes[2] = (value >> 8) & 0xFF;
        bytes[3] = value & 0xFF;         // 最低字节
    } else {
        bytes[0] = value & 0xFF;         // 最低字节
        bytes[1] = (value >> 8) & 0xFF;
        bytes[2] = (value >> 16) & 0xFF;
        bytes[3] = (value >> 24) & 0xFF; // 最高字节
    }
}




/********************************************************************************************
*函数功能:uint16 交换高低字节
*参数:    
*返回值:
********************************************************************************************/
uint16_t swap16(uint16_t val)
{
	return (val<<8)|((val>>8)&0x00FF);
}
/********************************************************************************************
*函数功能:uint32 交换高低字节
*参数:    
*返回值:
********************************************************************************************/
uint32_t swap32(uint32_t val)
{
	return ((val<<24)&0xFF000000)|((val<<8)&0x00FF0000)|((val>>8)&0x0000FF00)|((val>>24)&0xFF);
}
/********************************************************************************************
*函数功能:求绝对值
*参数:    
*返回值:
********************************************************************************************/
int64_t abs64(int64_t val)
{
	if(val > 0) return val;
	return (0-val);
}
/********************************************************************************************
*函数功能:求浮点数的绝对值
*参数:    
*返回值:
********************************************************************************************/
float abs_float(float val)
{
	if(val > 0) return val;
	return (0-val);
}



/********************************************************************************************
*函数功能:求最大值最小值的绝对值的差-整型
*参数:    
*返回值:
********************************************************************************************/

double get_relative_error(double max, double min) {
    // 计算绝对值
    double abs_max = abs_float(max);
    double abs_min = abs_float(min);
    
    // 处理两个值都为0的特殊情况
    if (abs_max == 0.0 && abs_min == 0.0) {
        return 0.0; // 或根据需求返回NaN/错误码
    }
    
    // 选择较大的绝对值作为分母，避免除零错误
    double denominator = (abs_max > abs_min) ? abs_max : abs_min;
    
    // 计算相对误差
    return abs_float(max - min) / denominator;
}
 

/********************************************************************************************
*函数功能:16进制数据格式化成字符串
*参数:    
*返回值:
********************************************************************************************/
void hex_to_string(char *string, char *hex, uint32_t num)
{
	uint32_t i, n;
	n = 0;
	for(i = 0; i < num; i ++)
	{
		sprintf(&string[n], "%02X ", (uint8_t)hex[i]);
		n += 3;
	}
	string[n] = 0;
}
/********************************************************************************************
*函数功能:颠倒字节序
*参数:    
*返回值:
********************************************************************************************/
void byte_seq_reverse(uint8_t *buf, uint32_t len)
{
	uint32_t i, j, n;
	uint8_t temp;
	if(len <= 1) return;
	n = len/2;//需要颠倒的次数
	for(i = 0; i < n; i ++)
	{
		temp = buf[i];
		j = len-1-i;
		buf[i] = buf[j];
		buf[j] = temp;
	}
}
/********************************************************************************************
*函数功能:modbus-RTU crc校验
*参数:    
*返回值:
********************************************************************************************/
uint16_t modbus_crc16(uint8_t *Bufdata, uint16_t Buflen) 
{
 	uint16_t crc=0xFFFF;
	uint8_t i, j;

	for ( j=0; j<Buflen;j++)
	{		
		crc=crc ^*Bufdata++;
		for ( i=0; i<8; i++)
		{
			if( ( crc&0x0001) >0)
			{
				crc=crc>>1;
				crc=crc^ 0xa001;
			}
			else
				crc=crc>>1;
		}
	}
	return (crc);
}
/********************************************************************************************
*函数功能:将字符串格式化成16进制字符串,注意此函数非进程安全，在加锁的条件下使用
*参数:    
*返回值:
********************************************************************************************/
char *hexToString(uint8_t *buf, uint16_t len)
{
	static char hex[200*3+20];
	if(len > 200){hex[0] = 0;}
	else{
		for(int i = 0; i < len; i ++)
		{
			sprintf(&hex[i*3], "%02X ", buf[i]);
		}
	}
	return hex;
}
/********************************************************************************************
*函数功能:温度格式化显示
*参数:    
*返回值: 
********************************************************************************************/
char *bsp_batTemp_format(int16_t temp)
{
	static char buf[20];
	if(temp < 0){sprintf(buf, "-%02d  ", abs(temp));}
	else{sprintf(buf, "+%02d  ", abs(temp));}
	return buf;
}
/********************************************************************************************
*函数功能:将指定bit位设置成指定的值
*参数:    var:要修改的值
		index:bit位索引，0-15
		val:要设置成的值，0或者1
*返回值: 
********************************************************************************************/
void uint16BitSet(uint16_t *var, uint8_t index, uint8_t val)
{
	uint16_t tmp = *var;
	if(val){tmp |= (1<<index);}
	else{tmp &= ~(1<<index);}
	*var = tmp;
}
/********************************************************************************************
*函数功能:将系统tick转换成时分秒
*参数:    
*返回值:
********************************************************************************************/
void tickToTime(uint32_t tick, uint16_t *hour, uint16_t *min, uint16_t *sec, uint16_t *ms)
{
	*hour = tick/(60*60*1000);
	*min = (tick%(60*60*1000))/(60*1000);
	*sec = (tick%(60*1000))/(1000);
	*ms = tick%1000;
}



/********************************************************************************************
*函数功能:计算世纪秒
*参数:    
*返回值:
********************************************************************************************/

/* 检查年份是否为闰年 */ 
static bool is_leap_year(uint16_t year) {
    if (year % 4 != 0) return false;
    if (year % 100 != 0) return true;
    if (year % 400 == 0) return true;
    return false;
}

/*  获取每个月的天数（考虑闰年） */
static uint8_t get_days_in_month(uint16_t year, uint8_t month) {
    static const uint8_t days_in_month[] = {31,28,31,30,31,30,31,31,30,31,30,31};
    
    if (month == 2 && is_leap_year(year)) {
        return 29;
    }
    return days_in_month[month - 1]; // 月份从1开始
}

/*
	计算从1970年1月1日00:00:00到指定日期时间的总秒数
	返回值：成功返回世纪秒，失败返回0（并通过参数指示错误）
*/  
 
uint64_t datetime_to_timestamp(uint16_t year, uint8_t month, uint8_t day, 
                              uint8_t hour, uint8_t minute, uint8_t second) 
{  
    // 基本范围检查
    if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
        hour > 23 || minute > 59 || second > 59) {
       
        return 0;
    }
    
    // 检查当月天数是否有效
    if (day > get_days_in_month(year, month)) {
       
        return 0;
    }
    
    uint64_t total_seconds = 0;
    
    // 计算年份贡献的秒数
    for (uint16_t y = 1970; y < year; y++) {
        if (is_leap_year(y)) {
            total_seconds += 31622400ULL; // 闰年：366天 × 86400秒/天
        } else {
            total_seconds += 31536000ULL; // 平年：365天 × 86400秒/天
        }
    }
    
    // 计算月份贡献的秒数
    for (uint8_t m = 1; m < month; m++) {
        total_seconds += (uint64_t)get_days_in_month(year, m) * 86400ULL;
    }
    
    // 计算天数、小时、分钟和秒的贡献
    total_seconds += (uint64_t)(day - 1) * 86400ULL;  // 天数（减1因为当天从0点开始）
    total_seconds += (uint64_t)hour * 3600ULL;        // 小时
    total_seconds += (uint64_t)minute * 60ULL;        // 分钟
    total_seconds += second;                          // 秒
    
    return total_seconds;
}





